#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>
#define  tamanhoTxt
#define  MASTER		0

char  *texto;
int *chunksizeAux, *offsetAux, *contador;



int main (int argc, char *argv[])
{
    int	numtasks,              /* number of tasks in partition */
    taskid,                /* a task identifier */
    numworkers,            /* number of worker tasks */
    source,                /* task id of message source */
    dest,                  /* task id of message destination */
    mtype,                  /* message type */
    rc, offset, i, j, tag1,
    tag2,  chunksize,in, tam, resp;

    char c, palavra[100];



    FILE *f;
    int inicio, fim, cont, n_caracteres_txt;

    /***** Initializations *****/

    MPI_Status status;

    rc = MPI_Init(&argc,&argv);
    MPI_Comm_rank(MPI_COMM_WORLD,&taskid);
    MPI_Comm_size(MPI_COMM_WORLD,&numtasks);
    if (numtasks < 2 )
    {
        printf("Need at least two MPI tasks. Quitting...\n");
        MPI_Abort(MPI_COMM_WORLD, rc);
        exit(1);
    }
    numworkers = numtasks-1;

    //printf ("MPI task %d has started...\n", taskid);
    tag2 = 1;
    tag1 = 2;

    f = fopen("wikipedia.txt", "r");

    fseek(f, 0, SEEK_END); //posiciona o cursor no fim do arquivo

    n_caracteres_txt = ftell(f); //a ultima posicao do arquivo é igual ao numero de caracteres no txt

    chunksize = (int)(n_caracteres_txt / (numtasks-1));

    /**************************** master task ************************************/
    if (taskid == 0)
    {
        resp = rc= offset = cont =0;


        texto = (char *) malloc(n_caracteres_txt*sizeof(char)); //alocando memoria para o numero total de caracteres do txt

        if(texto == NULL)
        {
            printf("Malloc devolveu NULL!\n");
            exit(1);
        }
        //printf("Task 0\n");
        fseek(f, 0, SEEK_SET); //posiciona o cursor no inicio do txt
        for(i=0; i<n_caracteres_txt; i++)  //para o primeiro caracter do txt, até o ultimo
        {
            texto[i] = fgetc(f); //copia o caracter para a memoria

            //if(!((texto[i] >= 48 && c <= 57) || (texto[i] >= 65 && c<= 90) || (texto[i] >= 97 && c<= 122)))
            cont++;
        }
        texto[n_caracteres_txt-1] = '\0';


        //printf("numero de letras = %d\n\n", cont);


        chunksizeAux = (int *) malloc(numtasks*sizeof(char));
        offsetAux = (int *) malloc(numtasks*sizeof(char));
        contador = (int *) malloc(numtasks*sizeof(char));

        for(i=0;  i<numtasks; i++)
        {
            chunksizeAux[i] = chunksize;
            offsetAux[i]= 0;
        }




        for (dest=0; dest<numtasks; dest++)
        {
            for(i=offsetAux[dest]+chunksize; i<n_caracteres_txt; i++)
            {

                if(!((texto[i] >= 48 && texto[i] <= 57) || (texto[i] >= 65 && texto[i]<= 90) || (texto[i] >= 97 && texto[i]<= 122)))
                {

                    if(dest!=numtasks-1)
                        offsetAux[dest+1] = offsetAux[dest] + chunksizeAux[dest];

                    //if(chunksizeAux[dest] + offsetAux[dest] > n_caracteres_txt)
                    break;
                }
                else
                {
                    chunksizeAux[dest] ++;
                    //  printf("ENTROU %d chunk: %d\n",dest, chunksizeAux[dest]);
                }
            }

            if(dest==numtasks-1)
            {
                chunksizeAux[dest] = n_caracteres_txt - offsetAux[dest];
            }



            /***************Send to Workers*******************/

            if(dest!=numtasks -1)
            {

                MPI_Send(&chunksizeAux[dest], 1, MPI_INT, dest+1, tag1, MPI_COMM_WORLD);
                MPI_Send(&texto[offsetAux[dest]], chunksizeAux[dest], MPI_CHAR, dest+1, tag2, MPI_COMM_WORLD);


                //printf("\n");
            }
        }

        /******************Recive from Workers*************/

        for (i=1; i<numtasks; i++)
        {
            MPI_Recv(&contador[i], 1, MPI_INT, i, tag1, MPI_COMM_WORLD, &status);
            resp += contador[i];
        }


        printf("---------Palindromos %d---------------\n", resp);


    }

    /**************************** worker task ************************************/
    if (taskid > 0)
    {
        //printf("Task %d\n", taskid);

        source =0;
        //rc = MPI_Recv(&offset, 1, MPI_INT, source, tag1, MPI_COMM_WORLD, &status);
        rc = MPI_Recv(&chunksize, 1, MPI_INT, source, tag1, MPI_COMM_WORLD, &status);

        texto = (char *) malloc(chunksize*sizeof(char));

        rc = MPI_Recv(&texto[0], chunksize, MPI_CHAR, source, tag2, MPI_COMM_WORLD, &status);

        cont =tam = 0;

        /************************calcular palindromo***************************/

        for(i=0; i<chunksize; i++) //para i=0 até i=numero de caracteres do txt
        {
            c = texto[i];

            if((c >= 48 && c <= 57) || (c >= 65 && c<= 90) || (c >= 97 && c<= 122))  //se for letra(maiuscula ou minuscula) ou numero
            {
                palavra[tam] = c; //adiciona o caracter ao vetor palavra
                tam++; //tamanho do vetor é incrementado
            }

            else if(c != 39)  // se c == ', ele nao faz nada. Vai pra proxima iteracao do while
            {
                if(palavra[0] != 0)  //se já tem algum caracter no vetor palavra, vai ser analisada a ocorrencia de palindromo
                {
                    inicio = 0;   //inicio da palavra
                    fim = tam-1;  //fim da palavra

                    if(tam % 2 == 1) //se a palavra tem numero impar de letras
                        tam = tam-1; //a iteração do for a seguir decrementada

                    for(inicio; inicio<(tam/2);)
                    {
                        if(palavra[inicio] != palavra[fim])  //se a primeira e ultima letra forem diferentes, nao é palindromo. O mesmo é verificado para as proximas letras
                        {
                            break;
                        }
                        else
                        {
                            if(inicio == (tam/2)-1)  //se chegar ao meio da palavra, quer dizer que é um palindromo
                            {
                                //   printf("\nPALINDROMO!!!!   >>>>   %s", palavra);
                                cont++; //contador de palindromos
                            }
                        }

                        inicio++; //incrementa a primeira letra
                        fim--;    //decrementa a ultima letra
                    }

                    for(inicio=0; inicio<=tam; inicio++) //zerando o vetor palavra
                        palavra[inicio] = 0;
                    tam = 0; //tamanho do vetor = 0
                }
            }
        }


        /**********************************************************************/

        MPI_Send(&cont, 1, MPI_INT, 0, tag1, MPI_COMM_WORLD);

        //Palindromos encontrados
        //printf("Task %d : %d\n\n",taskid,cont);
    }

    MPI_Finalize();

}
